﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProtoGame.GameLib;
using ProtoGame.DescritoresContent;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using ProtoGame.GameLib.Entities;

namespace ProtoGame.Sprites
{
    class PGSpriteFantasma : PGSpriteInimigo
    {
        enum StatesAcao
        {
            Andando,
            Perseguindo,
            PreparandoAtaque,
            Atacando
        }

        const float VelMovAndar = (800 / (4f * 60)) / 1.65f;
        const float VelMovAtacar = (800 / (4f * 60)) * 2.8f;

        // Em segundos
        const double StateSpanMin = 1.5;
        const double StateSpanMax = 6;
        const double StateSpanDelta = StateSpanMax - StateSpanMin;

        static Random random = new Random();

        float velMov = VelMovAndar;
        TimeSpan stateSpan = TimeSpan.Zero;
        Vector2 direcao = Vector2.Zero;

        TimeSpan tempoInvul = TimeSpan.Zero;
        int saude = -1;

        StatesAcao acao;

        SoundEffect gritoFala;
        SoundEffect gritoAtaca;
        SoundEffect gritoMorte;

        readonly int QtdeMaximaFantasmasLigados;

        public Stack<PGSpriteFantasma> FantasmasLigados { get; set; }
        public GraphicEntity JogadorAlvo { get; set; }

        public override Microsoft.Xna.Framework.Rectangle Bounds
        {
            get
            {
                // HACK: hardcoded :(
                Rectangle bounds = base.Bounds;
                bounds.Inflate(-39, -15);
                bounds.Y += 23 - 15;
                return bounds;
            }
        }

        public PGSpriteFantasma(int qtdeFantasmas, SoundEffect falaSfx, SoundEffect atacaSfx, SoundEffect morteSfx, Tileset gfx)
            : base(PGIMGSpriteFantasma.CriarAnimator(), gfx)
        {
            gritoFala = falaSfx;
            gritoAtaca = atacaSfx;
            gritoMorte = morteSfx;

            FantasmasLigados = new Stack<PGSpriteFantasma>(1);
            FantasmasLigados.Push(this);
            QtdeMaximaFantasmasLigados = qtdeFantasmas;
        }

        public override void Update(GameTime gameTime)
        {
            stateSpan -= gameTime.ElapsedGameTime;
            tempoInvul -= gameTime.ElapsedGameTime;

            if (stateSpan <= TimeSpan.Zero)
                EscolheNovaAcao();

            if (acao == StatesAcao.Perseguindo)
                PerseguirNovaDirecao();

            Velocity = direcao * velMov;

            AtualizaFade();

            base.Update(gameTime);
        }

        private void AtualizaFade()
        {
            Fade = (byte)(byte.MaxValue * (FantasmasLigados.Count / (float)QtdeMaximaFantasmasLigados));
        }

        private void EscolheNovaAcao()
        {
            if (acao != StatesAcao.PreparandoAtaque)
            {
                int novaAcao = random.Next(3);
                switch (novaAcao)
                {
                    case 0: AcaoAndar(); break;
                    case 1: AcaoPerseguir(); break;
                    case 2: AcaoPrepararAtaque(); break;
                }
            }
            else
                AcaoAtacar();            
        }

        private void AcaoAtacar()
        {
            velMov = VelMovAtacar;
            stateSpan = TimeSpan.FromSeconds(StateSpanMax);
            acao = StatesAcao.Atacando;
        }

        private void AcaoPrepararAtaque()
        {
            int x = JogadorAlvo.Bounds.Center.X - Bounds.Center.X;
            int y = JogadorAlvo.Bounds.Center.Y - Bounds.Center.Y;
            direcao = new Vector2(x, y);

            if (direcao != Vector2.Zero)
            {
                velMov = 0f;
                direcao.Normalize();
            }

            AnimationState = PGIMGSpriteFantasma.StateAtacando;
            acao = StatesAcao.PreparandoAtaque;
            stateSpan = TimeSpan.FromSeconds(StateSpanMin);

            gritoAtaca.Play();
        }

        private void AcaoPerseguir()
        {
            PerseguirNovaDirecao();

            AnimationState = PGIMGSpriteFantasma.StateNormal;
            acao = StatesAcao.Perseguindo;
            stateSpan = TimeSpan.FromSeconds(StateSpanMin + (StateSpanDelta * random.NextDouble()));

            gritoFala.Play();
        }

        private void PerseguirNovaDirecao()
        {
            int x = JogadorAlvo.Bounds.Center.X - Bounds.Center.X;
            int y = JogadorAlvo.Bounds.Center.Y - Bounds.Center.Y;
            direcao = new Vector2(x, y);

            if (direcao != Vector2.Zero)
            {
                velMov = VelMovAndar;
                direcao.Normalize();
            }
        }

        private void AcaoAndar()
        {

            direcao = new Vector2((float)random.NextDouble(), (float)random.NextDouble());
            direcao.X *= random.NextDouble() > 0.5 ? -1 : 1;
            direcao.Y *= random.NextDouble() > 0.5 ? -1 : 1;

            if (direcao != Vector2.Zero)
            {
                velMov = VelMovAndar;
                direcao.Normalize();
            }

            AnimationState = PGIMGSpriteFantasma.StateNormal;
            acao = StatesAcao.Andando;
            stateSpan = TimeSpan.FromSeconds(StateSpanMin + (StateSpanDelta * random.NextDouble()));
        }

        protected override void MudaDirecao()
        {
            direcao = -direcao;
        }

        protected override void RecebeAtaque()
        {
            if (FantasmasLigados.Peek() == this && tempoInvul <= TimeSpan.Zero)
            {
                gritoMorte.Play();
                if (saude < 0)
                    saude = Math.Max(FantasmasLigados.Count - 2, 1);

                saude--;
                tempoInvul = TimeSpan.FromSeconds(0.5);

                if (saude < 1)
                {
                    FantasmasLigados.Pop();
                    Visible = false;
                    Alive = false;
                }
            }
        }
    }
}
